package utils

import (
	"logging"
	"time"
)

//常见的errno定义
const (
	ErrComm             = -1    //通用错误
	ErrDB               = 99    //数据库操作异常
	ErrBindJSON         = 98    //参数绑定异常
	ErrJSONFormat       = 97    //JSON数据解析异常
	ErrDataTypeFormat   = 96    //数据类型转化异常
	ErrHttpApi          = 95    //内部服务请求异常
	ErrIO               = 94    //IO异常
	ErrUserNotFoundAuth = 10001 //未找到用户权限
)

type LogInfo struct {
	RequestID string //使用用户标识+时间戳作为唯一ID
}

// 规范日志打印，后期统一使用消息队列打印日志
type Log struct {
	RequestID   string `json:"request_id" bson:"-"`        //使用用户标识+时间戳作为唯一ID
	ServiceName string `json:"service_name" bson:"-"`      //服务名称
	FuncName    string `json:"func_name" bson:"func_name"` //方法名（方便快速定位错误）
	//节点类型  1:开始节点   2:普通节点(最多)   3:判断节点  4:存储节点（包括add,update,delete,query）
	// 5:错误节点  6:成功结束节点 7:失败结束节点  8:内部http调用
	NodeType      int           `json:"node_type" bson:"node_type"`
	NodeName      string        `json:"node_name" bson:"node_type"`           //节点名称  尽量用中文 比如：获取用户详情、判断是否是管理员 、保存用户详情
	Errno         int           `json:"errno" bson:"errno"`                   //错误编码 0:正常   其它:异常
	Errmsg        string        `json:"errmsg" bson:"errmsg"`                 //错误信息
	Format        string        `json:"-" bson:"-"`                           //节点信息打印模板
	Args          []interface{} `json:"-" bson:"-"`                           //节点信息的参数
	FormatContent string        `json:"format_content" bson:"format_content"` // 节点参数打印
	LogTime       int64         `json:"log_time" bson:"log_time"`             //节点时间
	ErrContent    string        `json:"err_content" bson:"err_content"`       //错误详细信息
	LogInfo       *LogInfo      `json:"-" bson:"-"`
}

func (logInfo *LogInfo) NewLog(funcName string) *Log {
	log := &Log{RequestID: logInfo.RequestID, FuncName: funcName}
	log.LogInfo = logInfo
	return log
}

func (log *Log) Start(nodeName string) {
	log.NodeType = 1
	log.LogTime = time.Now().UnixNano() / 1e6
	log.NodeName = nodeName
	logging.Debugf("request_id:%v func_name:%v node_type:%v node_name:%v log_time:%v\n",
		log.RequestID, log.FuncName, log.NodeType, log.NodeName, log.LogTime)
}

// debug日志打印，一般debug记住了整个流程数据，方便后期做数据回滚
func (log *Log) DebugDB(nodeName string, format string, args ...interface{}) {
	log.LogTime = time.Now().UnixNano() / 1e6
	log.NodeType = 4
	log.NodeName = nodeName
	log.Format = format
	log.Args = args
	slice := ArgMerge(log.RequestID, log.FuncName, log.NodeType, log.NodeName, args, log.LogTime)
	logging.Debugf("request_id:%v func_name:%v node_type:%v node_name:%v "+format+" log_time:%v\n", slice...)
}

// debug日志打印
func (log *Log) DebugJudge(nodeName string, format string, args ...interface{}) {
	logTime := time.Now().UnixNano() / 1e6
	log.LogTime = logTime
	log.NodeType = 3
	log.Format = format
	log.Args = args
	log.NodeName = nodeName
	slice := ArgMerge(log.RequestID, log.FuncName, log.NodeType, log.NodeName, args, log.LogTime)
	logging.Debugf("request_id:%v func_name:%v node_type:%v node_name:%v "+format+" log_time:%v\n", slice...)
}

// 内部http调用日志
func (log *Log) DebugHttp(nodeName string, format string, args ...interface{}) {
	log.LogTime = time.Now().UnixNano() / 1e6
	log.NodeType = 8
	log.Format = format
	log.Args = args
	log.NodeName = nodeName
	slice := ArgMerge(log.RequestID, log.FuncName, log.NodeType, log.NodeName, args, log.LogTime)
	logging.Debugf("request_id:%v func_name:%v node_type:%v node_name:%v "+format+" log_time:%v\n", slice...)
}

// debug日志打印，一般debug记住了整个流程数据，方便后期做数据回滚
func (log *Log) Debug(nodeName string, format string, args ...interface{}) {
	log.LogTime = time.Now().UnixNano() / 1e6
	log.NodeType = 2
	log.Format = format
	log.Args = args
	log.NodeName = nodeName
	slice := ArgMerge(log.RequestID, log.FuncName, log.NodeType, log.NodeName, args, log.LogTime)
	logging.Debugf("request_id:%v func_name:%v node_type:%v node_name:%v "+format+" log_time:%v\n", slice...)
}

//记住错误信息
func (log *Log) Error(errno int, errmsg string, err error) {
	log.NodeType = 5
	log.LogTime = time.Now().UnixNano() / 1e6
	log.Errno = errno
	log.Errmsg = errmsg
	log.NodeName = errmsg
	if err != nil {
		log.ErrContent = err.Error()
	}
	logging.Errorf("request_id:%v func_name:%v node_type:%v errno:%v errmsg:%v log_time:%v err:%v\n",
		log.RequestID, log.FuncName, log.NodeType, errno, errmsg, log.LogTime, log.ErrContent)

}

//错误终结了流程
func (log *Log) ErrorEnd(errno int, errmsg string, err error) interface{} {
	log.NodeType = 7
	log.LogTime = time.Now().UnixNano() / 1e6
	responeObj := make(map[string]interface{})
	responeObj["errno"] = errno
	responeObj["errmsg"] = errmsg
	if err != nil {
		log.ErrContent = err.Error()
	}
	log.Errno = errno
	log.Errmsg = errmsg
	log.NodeName = errmsg
	logging.Errorf("request_id:%v func_name:%v node_type:%v errno:%v errmsg:%v log_time:%v err:%v\n",
		log.RequestID, log.FuncName, log.NodeType, errno, errmsg, log.LogTime, log.ErrContent)

	return responeObj
}

// 成功数据返回
func (log *Log) SuccessEnd(nodeName string, data interface{}) interface{} {
	log.NodeType = 6
	responeObj := make(map[string]interface{})
	responeObj["errno"] = 0
	responeObj["errmsg"] = nodeName
	if data != nil {
		responeObj["data"] = data
	}
	log.NodeName = nodeName
	log.LogTime = time.Now().UnixNano() / 1e6
	logging.Infof("request_id:%v func_name:%v node_type:%v node_name:%v log_time:%v\n",
		log.RequestID, log.FuncName, log.NodeType, nodeName, log.LogTime)

	return responeObj
}

func ArgMerge(args ...interface{}) []interface{} {
	new_args := make([]interface{}, 0)
	for _, v := range args {
		switch v2 := v.(type) {
		case []interface{}:
			for _, a := range v2 {
				new_args = append(new_args, a)
			}
		default:
			new_args = append(new_args, v2)
		}
	}
	return new_args
}
